# coding: utf-8 -*-
# author: 梁开孟
# date：2021/11/27 0027 19:52

import warnings
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from toad.transform import Combiner
from sklearn.linear_model import LogisticRegression, Lasso, Ridge
from sklearn.svm import SVC
from sklearn.tree import DecisionTreeClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import AdaBoostClassifier, GradientBoostingClassifier
from sklearn.ensemble import RandomForestClassifier, ExtraTreesClassifier
from sklearn.ensemble import VotingClassifier
from lightgbm import LGBMClassifier
from xgboost import XGBClassifier
from catboost import CatBoostClassifier
from sklearn.model_selection import KFold, cross_val_score, train_test_split
from sklearn.metrics import roc_auc_score, f1_score, classification_report, confusion_matrix
from sklearn.utils import shuffle

warnings.filterwarnings('ignore')
pd.set_option('display.width', 500)
pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', None)
plt.rcParams['font.sans-serif'] = ['FangSong']
plt.rcParams['axes.unicode_minus']=False


def feature_bins(data, target='TARGET', method='chi', exlist=['ID', 'TARGET']):
    """
    特征分箱
    @param data: 训练数据集
    @param target: 目标变量
    @param method: 方法，chi、dt
    @param exlist: 不参与的字段
    @return: 分箱模型
    """
    combiner = Combiner()
    combiner.fit(data, data[target],
                 method=method,
                 min_samples=0.05,
                 exclude=exlist)

    return combiner


def confrontation_verification(train, test, tag=True, drop_col=['ID', 'TARGET']):
    """
    对抗验证
    @param train: 数据集1
    @param test: 数据集2
    @param tag: 是否删除字段
    @param drop_col: 删除字段列表，如果tag为True
    @return: 对抗结果
    """
    train['lab'] = 1
    test['lab'] = 0
    data = shuffle(train.append(test))
    data.index = range(len(data))
    if tag:
        data.drop(drop_col, axis=1, inplace=True)

    i = 1
    res = {}
    while i <= 50:
        random_state = int(np.random.randint(1, 10000000, 1))
        x_train, x_test, y_train, y_test = train_test_split(data.iloc[:, :-1], data.iloc[:, -1],
                                                            test_size=0.3,
                                                            random_state=random_state)

        model = LogisticRegression(class_weight='balanced', random_state=2021)
        score = cross_val_score(model, x_train, y_train, cv=10, n_jobs=-1, scoring='roc_auc').mean()

        res[random_state] = score
        print('第{}次迭代，随机种子为：{}，AUC为：{}'.format(i, random_state, score))
        i += 1

    for key, value in res.items():
        if (value == max(res.values())):
            print('最终随机种子为：{}，AUC为：{}'.format(key, value))


def metrics_score(model, x_train, x_test, y_train, y_test):
    print('训练集评估：')
    train_pred = model.predict(x_train)
    print('f1-score：', f1_score(y_train, train_pred))
    print('roc_auc_score：', roc_auc_score(y_train, train_pred))
    print('分类报告：\n', classification_report(y_train, train_pred))
    print('混淆矩阵：\n', confusion_matrix(y_train, train_pred))

    print('测试集评估：')
    test_pred = model.predict(x_test)
    print('f1-score：', f1_score(y_test, test_pred))
    print('roc_auc_score：', roc_auc_score(y_test, test_pred))
    print('分类报告：\n', classification_report(y_test, test_pred))
    print('混淆矩阵：\n', confusion_matrix(y_test, test_pred))


def run(train, test):
    chi_model = feature_bins(train)
    chi_train = chi_model.transform(train)
    chi_test = chi_model.transform(test)

    x_train, x_test, y_train, y_test = train_test_split(chi_train.iloc[:, 1:-1],
                                                        chi_train.iloc[:, -1],
                                                        test_size=0.3,
                                                        random_state=2021)

    confrontation_verification(chi_train, chi_test, tag=True)

    model = LGBMClassifier(class_weight='balanced', random_state=2021)
    model.fit(x_train, y_train)

    metrics_score(model, x_train, x_test, y_train, y_test)


if __name__ == '__main__':
    train = pd.read_csv('data/df_training.csv', encoding='utf-8')
    test = pd.read_csv('data/df_test.csv', encoding='utf-8')
    run(train, test)
